/*
 * CopyRight(C) Kenbin
 */

#ifndef LSG_FILEBUCKET_INCLUDED
#define LSG_FILEBUCKET_INCLUDED

/*Comment#
   文件桶，实现buddyfile的群组管理，一个文件桶最多包含MAX_FILE_CNT个文
   件，可以控制最大同时打开的文件数量。读写数据块具备一定的容错性。
*/

namespace LSG {

    class CBuddyFile;

    class CFileBucket
    {
	public:
	    enum { PHYSICID_LEN = 64, MAX_FILE_CNT = 16 };
	    enum { WRITER_NOSET = -1 };
	    enum { 
		FILESEQ_NOUSE = 1, 
		FILESEQ_USED = 2, 
		FILESEQ_LOADED = 3, 
		FILESEQ_ERR = -1 
	    };

	    CFileBucket(const char *base_path, int block_size, 
		    int block_count, int loaded_max);
	    ~CFileBucket();

	    /* physic_id :<block_size>.<file_seq>.<buddybit_offset> */

	    /* ok, return buddybit_offset; fail, return < 0 */
	    int Save(char *physic_id, char *data, int data_len, int reserve = 0);
	    /* ok, return 0; fail, return < 0 */
	    int Update(const char *physic_id, int byte_offset,
		    char *data, int data_len, int reserve = 0);
	    /* ok, return 0; fail, return < 0 */
	    int Read(const char *physic_id, char **data,
		    int *data_len, int *reserve = NULL);
	    /* ok, return 0; fail, return < 0 */
	    int Delete(const char *physic_id);

	public:
	    bool Error() const
	    {
		if(m_errid != 0) {
		    return true;
		}

		return false;
	    }

	    const char *ErrMsg()
	    {
		switch(m_errid) {
		    case 1: return "invalid block_size";
		    case 2: return "invalid block_count";
		    case 3: return "file size exceed 2G";
		    case 4: return "invalid loaded_max";
		    case 5: return strerror(m_errno);
		    default: return "undefined";
		}
	    }

	private:
	    int verify_buddyfile(int file_seq, int *alloced);

	    int try_alloc_writer();
	    int alloc_writer();

	    int choose_buddyfile(const char *physic_id, int *file_seq, 
		    int *buddybit_offset, CBuddyFile **buddyfile_obj);
	    int recycle_buddyfile(int file_seq);

	    int load_buddyfile(int file_seq);
	    int unload_buddyfile(int file_seq);

	    int open_buddyfile(int file_seq);
	    int close_buddyfile(int file_seq);

	    char *get_filename(int file_seq, char *filename, int len);

	    struct BuddyFile
	    {
		class CBuddyFile *obj;
		int flag;
		int alloced;
		unsigned opentime;
		unsigned lasttime;
		unsigned access_count;
	    };

	    char m_base_path[256];

	    int m_block_size;
	    int m_block_count;
	    int m_loaded_max;
	    int m_loaded_count;

	    BuddyFile m_buddyfiles[MAX_FILE_CNT];
	    int m_writer;

	    int m_errid;
	    int m_errno;
    };

};

#endif
